#!/usr/bin/python
# -*- coding: UTF-8 -*-

import json
import re

import requests
from bs4 import BeautifulSoup

from enums.sys_type_enum import SysTypeEnum
from utils.commit.oversea_regions import OVERSEA_REGIONS
from utils.commit.submit_tx import SubmitTypeEnum
from utils.commit.submit_wjx_v2 import QuestionareSpider
from utils.common.init_app import app
from utils.ip_proxy.pinzan_ip_proxy import PinzanHttpProxy
from utils.submit_ua import UserAgentGenerate

session = requests.Session()


class QuestionareSpiderCredamo(QuestionareSpider):
    def __init__(self, send_title_link, pz_obj, wo_topic_id, sleep_time, area):
        self.sessions = session
        # self.proxy_obj = proxy_obj
        self.pz_obj: PinzanHttpProxy = pz_obj
        self.title_link = send_title_link
        self.wo_topic_id = wo_topic_id
        self.headers = {}
        self.sleep_time = sleep_time or 20  # 问卷需要填写的时间,默认20秒
        self.area = area
        self.ua = UserAgentGenerate.random_phone_micro_messenger()  # 初始化实例默认获取一个ua
        self.can_get_7_code = True

    def get_answer_token(self):
        """
        获取answerToken
        :return:
        """
        url_id = self.title_link.split()[-1]
        url = f'https://www.credamo.com/v1/survey/answer/noauth/init/{url_id}?accountCode=CDM&resolution=1920px*1080px'
        header = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/95.0.4638.69 Safari/537.36',
        }
        response = requests.get(url, headers=header, timeout=10)
        content = json.loads(response.content)
        answer_token = content['data']['answerToken']
        return answer_token

    def get_submit_result(self, submitdata, submit_type):
        """
        提交问卷
        :param submitdata: 需要提交数据
        :return:
        """

        # 1. 构建提交参数
        cur_header = dict()
        cur_header['user-agent'] = self.ua  # 模拟微信请求头
        # app.logger.debug(f'cur_header={cur_header}')
        answer_token = self.get_answer_token()
        url = 'https://www.credamo.com/v1/survey/answer/noauth/save?answerToken=' + answer_token
        # app.logger.debug(f'url={url}')
        # app.logger.debug(f'submitdata={submitdata}')
        # 2. 判断ip是否可用
        self.is_ip_available()  # 判断当前ip是否过期，如果过期重新获取一个ip并且立即发送请求
        # 3. 发送请求
        # app.logger.debug(f'area：{self.area}')
        if self.area in OVERSEA_REGIONS:  # 海外发送请求
            # app.logger.debug('发送到海外服务器')
            # 1, 获取海外的代理地址，2，发送到海外服务器
            upper_area = self.area.upper()
            p_url = 'http://wisienkax_area-' + upper_area + ':123456zzz@proxy.smartproxycn.com:1000'
            oversea_param_dict = dict()
            oversea_param_dict['submit_data'] = {'submitdata': submitdata}
            oversea_param_dict['request_headers'] = cur_header
            oversea_param_dict['proxy_url'] = p_url
            oversea_send_url = url + '?'
            encoded_url = oversea_send_url
            oversea_param_dict['url'] = encoded_url
            # app.logger.debug('打印请求参数：')
            # app.logger.debug(oversea_param_dict)
            sys_oversea_url = 'http://8.137.54.97:7002/api/overseas/submit'
            oversea_header = dict()
            # oversea_header['content-type'] = 'application/json; charset=UTF-8'
            res = requests.post(url=sys_oversea_url, headers=oversea_header, data=submitdata, timeout=10, proxies=self.pz_obj.proxies)
            oversea_response = res.json()
            if oversea_response and 200 == oversea_response.get('code'):
                pd = oversea_response.get('result')
            else:
                pd = '发送海外数据失败'
        else:  # 默认国内直接发送
            res = requests.post(url=url, headers=cur_header, data=submitdata, timeout=10, allow_redirects=False)
            pd = res.content.decode()
        app.logger.info(f'response_data={pd}')
        return pd

    def submit(self, submitdata):
        """
        提交问卷
        :param submitdata: 需要提交数据
        :return:
        """
        pd = self.get_submit_result(submitdata, SubmitTypeEnum.WX)  # 默认微信提交
        if pd.startswith('10〒'):
            pass
        elif pd.startswith('5〒'):  # 5〒很抱歉，必须微信登录才能填写！
            # 默认就是微信提交，说明此时不应该再用微信提交，则转为使用手机提交
            self.ua = UserAgentGenerate.random_pc()  # 获取pd的ua
            pd = self.get_submit_result(submitdata, SubmitTypeEnum.PHONE)
        elif pd.startswith('7〒'):  # 需要智能验证
            pass
        else:
            pass
        return pd


def convert_data_to_submit_data(db_title_arr, db_res_arr, link) -> str:
    """
    将数据库中的数据转换为需要提交的结果数据
    :param db_title_arr: 题目与数据库结果的映射关系数组
    :param db_res_arr: 需要提交的答案数组
    :param link: 初始URL链接
    :return:
    """
    header = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
    }
    response = requests.get(link, allow_redirects=False, headers=header, timeout=10)
    content = response.content
    # 使用 BeautifulSoup 解析页面内容
    soup = BeautifulSoup(response.content, 'html.parser')
    find_result = soup.find_all(string=re.compile("FB_PUBLIC_LOAD_DATA_"), limit=1)
    if len(find_result) < 1:
        # app.logger.debug("未找到数据")
        raise Exception("未找到数据")
    ret = str(find_result[0])
    ret_arr = ret.split('=')
    src_data = ret_arr[1][:-1]

    # 构造提交数据
    form = soup.find(name='form')
    attrs = str(form).split()
    fbzx = ''
    for attr in attrs:
        if attr.startswith('data-shuffle-seed'):
            tmp_arr = attr.split('=')
            fbzx = tmp_arr[1]
    # app.logger.debug(fbzx)
    fbzx = fbzx[1:-1]
    res = {'fvv': 1,
           'partialResponse': '[null,null,' + fbzx + ']',
           'pageHistory': '0',  # 页码从0开始
           'fbzx': fbzx
           }

    page_id_list = list()
    for index in range(len(db_title_arr)):
        i = db_title_arr[index]
        if 'data_index' not in i:  # if not hasattr(i, 'data_index'):
            continue
        indexes = i['data_index']
        cur_type = i['sys_type']
        options = i['options']
        page_id = str(i['page_id'])
        ans_id = ''
        if cur_type == SysTypeEnum.SINGLE.value:  # 单选题
            # 数据格式：{"entry.1041616889": "单选项1"}
            cur_value = str(db_res_arr[indexes[0]])
            if '-3' == cur_value:  # -3直接跳过这条数据
                continue
            for option in options:
                if str(option['value']) == cur_value:  # 所有数据转换为字符串进行比较
                    ans_id, opt_name = option['real_value'].split(':')
                    key = 'entry.' + ans_id
                    if str(option['name']).endswith('|underline'):
                        res[key] = '__other_option__'
                        key_add = key + '.other_option_response'
                        res[key_add] = '无'
                    else:
                        val = opt_name
                        res[key] = val
                    break
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
        elif cur_type == SysTypeEnum.MULTIPLE.value:  # 多选题
            # 数据格式：{"entry.1397809770": ["多选项3","多选项4"]}
            key = ''
            val_list = list()
            is_jump = False
            for option in options:
                db_value = str(db_res_arr[option['data_index']])
                if '-3' == db_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                if '1' != db_value:
                    continue
                ans_id, opt_name = option['real_value'].split(':')
                key = 'entry.' + ans_id
                val_list.append(opt_name)
            if is_jump:
                continue
            res[key] = val_list
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
        elif cur_type == SysTypeEnum.SINGLE_SELECT.value:  # 下拉单选题
            # 数据格式：{"entry.1343972306": "下拉选项2"}
            cur_value = str(db_res_arr[indexes[0]])
            if '-3' == cur_value:  # -3直接跳过这条数据
                continue
            for option in options:
                if str(option['value']) == cur_value:  # 所有数据转换为字符串进行比较
                    ans_id, opt_name = option['real_value'].split(':')
                    key = 'entry.' + ans_id
                    val = opt_name
                    res[key] = val
                    break
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
        elif cur_type == SysTypeEnum.SCALE.value:  # 单选量表题
            # 数据格式：{"entry.1224417829": "4"}
            selected_value = str(db_res_arr[indexes[0]])
            if '-3' == selected_value:  # -3直接跳过这条数据
                continue
            ans_id, opt_name = options[0]['real_value'].split(':')
            key = 'entry.' + ans_id
            res[key] = selected_value
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
        elif cur_type == SysTypeEnum.TEXT.value:  # 填空题
            # 数据格式_日期：{"entry.2033375724_year": "2024","entry.2033375724_month": "2","entry.2033375724_day": "6"}
            # 数据格式：{"entry.2010275003": "填空内容"}
            src_type = i['title_type']
            idx = indexes[0]
            filled_value = str(db_res_arr[indexes[0]])
            if '-3' == filled_value:  # -3直接跳过这条数据
                continue
            ans_id = str(options[0]['real_value'])
            if 9 == src_type:  # 日期，格式：年/月/日
                year_key = 'entry.' + ans_id + '_year'
                month_key = 'entry.' + ans_id + '_month'
                day_key = 'entry.' + ans_id + '_day'
                if '/' not in filled_value:  # 无/符号说明非日期格式
                    res[year_key] = ''
                    res[month_key] = ''
                    res[day_key] = ''
                else:
                    year_val, month_val, day_val = filled_value.split('/')
                    res[year_key] = year_val
                    res[month_key] = month_val  # str(int(month_val))  # 将类似02变为2
                    res[day_key] = day_val  # str(int(day_val))
            elif 10 == src_type:  # 时间，格式： 时:分
                hour_key = 'entry.' + ans_id + '_year'
                minute_key = 'entry.' + ans_id + '_month'
                if ':' not in filled_value:  # 无:符号说明非时间格式
                    res[hour_key] = ''
                    res[minute_key] = ''
                else:
                    hour_val, minute_val = filled_value.split(':')
                    res[hour_key] = hour_val
                    res[minute_key] = minute_val
            else:
                key = 'entry.' + ans_id
                res[key] = filled_value
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
        elif cur_type == SysTypeEnum.MATRIX.value:  # 单选矩阵题
            # 数据格式：{"entry.284073369": "第 5 列", "entry.57368770": "第 3 列"}
            children = i['children']
            counter = 0
            is_jump = False
            for cur_child in children:
                ans_id = str(cur_child['real_value'])
                key = 'entry.' + ans_id
                sentinel_key = 'entry.' + ans_id + '_sentinel'
                options = cur_child['options']
                cur_value = str(db_res_arr[indexes[counter]])
                if '-3' == cur_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                for option in options:
                    if str(option['value']) == cur_value:
                        opt_name = option['name']
                        res[key] = opt_name
                        res[sentinel_key] = ''
                        break
                counter += 1
            if is_jump:
                continue
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
            continue  # 这里加这个是为了不走到“sentinel字段的设置”这一步，因为这里的特殊情况已经设置
        elif cur_type == SysTypeEnum.CASCADE_DROPDOWN.value:  # 级联下拉题
            pass  # 暂无
        elif cur_type == SysTypeEnum.SLIDE.value or cur_type == SysTypeEnum.RATE.value:  # 滑动条或者比重题
            pass  # 暂无
        elif cur_type == SysTypeEnum.SORTED.value:  # 排序题
            pass  # 暂无
        elif cur_type == SysTypeEnum.MULTIPLE_TEXT.value:  # 多项填空
            pass  # 暂无
        elif cur_type == SysTypeEnum.MULTIPLE_MATRIX.value:  # 矩阵多选
            # 数据格式：{"entry.1892436430": "第 4 列","entry.1184361657": "第 3 列","entry.1495404203": "第 2 列"}
            children = i['children']
            counter = 0
            is_jump = False
            for cur_child in children:  # 每个child代表一行
                ans_id = str(cur_child['real_value'])
                key = 'entry.' + ans_id
                sentinel_key = 'entry.' + ans_id + '_sentinel'
                options = cur_child['options']
                val_list = list()
                for option in options:
                    db_value = str(db_res_arr[option['data_index']])
                    if '-3' == db_value:  # -3直接跳过这条数据
                        is_jump = True
                        break
                    if '1' != db_value:
                        continue
                    opt_name = option['name']
                    val_list.append(opt_name)
                if is_jump:
                    break
                res[key] = val_list
                res[sentinel_key] = ''
                counter += 1
            if is_jump:
                continue
            # 页码插入（如果不存在列表中）
            if page_id not in page_id_list:
                page_id_list.append(page_id)
            continue  # 这里加这个是为了不走到“sentinel字段的设置”这一步，因为这里的特殊情况已经设置
        elif cur_type == SysTypeEnum.MATRIX_TEXT.value:  # 矩阵填空
            pass  # 暂无
        else:  # 未知
            pass
        # 添加sentinel字段的设置。下拉，日期和填空这3个不用设置sentinel
        if cur_type != SysTypeEnum.SINGLE_SELECT.value and cur_type != SysTypeEnum.TEXT.value:
            sentinel_key = 'entry.' + ans_id + '_sentinel'
            res[sentinel_key] = ''
    page_ids = ",".join(page_id_list)
    res['pageHistory'] = page_ids
    app.logger.debug(f'res={json.dumps(res)}')
    return res


def do_submit(proxy_region: str, send_title_link: str, submitdata: str, sleep_time: int, wo_topic_id):
    # app.logger.debug(f'do_submit提交数据，wo_topic_id:{wo_topic_id}')
    # 获取品赞代理
    virtual_proxy_area = proxy_region
    if proxy_region in OVERSEA_REGIONS:  # 海外发送请求，默认先使用国内的'全国'请求地址，最后发送的时候改为获取海外的ip
        virtual_proxy_area = 'all'
    pz_obj = PinzanHttpProxy(virtual_proxy_area)
    pz_obj.get_proxy()
    # 创建问卷对象, 发送请求
    qo = QuestionareSpiderCredamo(send_title_link=send_title_link, pz_obj=pz_obj, wo_topic_id=wo_topic_id,
                             sleep_time=sleep_time, area=proxy_region)
    res = qo.submit(submitdata)  # 提交
    # app.logger.debug(submitdata)
    return res, pz_obj.host_port_city


def get_simple_result(request_res):
    """获取简单结果(提取关键部分，减少不必要的入库字符串长度)"""
    soup = BeautifulSoup(request_res, 'html.parser')
    find_result = soup.find(name='div', class_='idZHHb')
    app.logger.debug(f'find_result:{find_result}')
    return str(find_result)


# Press the green button in the gutter to run the script.
if __name__ == '__main__':

    pass
